import {MicroAppModule} from "./MicroAppModule";
import {designComponent, globalComputed, reactive} from "@peryl/react-compose";
import {createBrowserHistory, iHistoryMeta, iMicroApp, iMicroConfig, iMicroLayoutRouteConfig, iMicroPageRouteConfig, iRouteKey, path2regexp, pathJoin} from "@peryl/micro-web";

export const microAppRoute = MicroAppModule.createRegistration((microApp) => {

  let history: ReturnType<typeof createBrowserHistory> | undefined = undefined;

  const state = reactive({
    route: null as null | iHistoryMeta,
    layoutRouteConfigs: [] as iMicroLayoutRouteConfig[],
    pageRouteConfigs: [] as iMicroPageRouteConfig[]
  });

  /**
   * 定义layout路由
   * @author  韦胜健
   * @date    2024/5/8 15:34
   */
  const defineLayoutRoute = (route: iMicroLayoutRouteConfig) => {state.layoutRouteConfigs.unshift(route);};

  /**
   * 定义page路由
   * @author  韦胜健
   * @date    2024/5/8 15:34
   */
  const definePageRoute: iMicroApp["route"]["definePageRoute"] = (_pageRouteConfig) => {
    const routeKeys: iRouteKey[] = [];
    const routePatten = path2regexp(_pageRouteConfig.route, routeKeys, { end: false });
    state.pageRouteConfigs.unshift({
      ..._pageRouteConfig,
      routeKeys: routeKeys.map(i => String(i.name)),
      routePatten,
    });
  };

  const matchPageRoute: iMicroApp["route"]["matchPageRoute"] = (path) => {
    let routeMatch: string[] = [];
    const pageRouteConfig = state.pageRouteConfigs.find(i => {
      const _routeMatch = path.match(i.routePatten);
      // console.log(_routeMatch, i.routePatten, i.routeKeys);
      if (!!_routeMatch) {routeMatch = _routeMatch;}
      return !!_routeMatch;
    });
    if (!pageRouteConfig) {return undefined;}
    let [, ...values] = routeMatch!;
    const routeParams = values.reduce((prev, val, index) => {
      prev[pageRouteConfig.routeKeys[index]] = val;
      return prev;
    }, {} as Record<string, any>);
    return { ...pageRouteConfig, routeParams };
  };

  const currentRoute = globalComputed(() => {

    if (!history) {
      history = createBrowserHistory({
        base: (() => {
          const val = microApp.baseRoutePublicPath.get();
          if (/https?:\/\//.test(val)) {
            return (new URL(val)).pathname;
          } else {
            return val;
          }
        })()
      });
      history.onPathChange(() => {state.route = history!.state.route;});
      refer.history = history;
      state.route = history.state.route;
    }

    const { route } = state;
    if (!route) {throw new Error('路由初始化异常！');}
    let path = pathJoin('/' + route.path + '/');
    return state.layoutRouteConfigs.find(i => path.indexOf(pathJoin('/' + i.path + '/')) === 0);
  });

  const Render = designComponent({
    name: 'micro-app-route-render',
    setup() {

      if (!currentRoute.value) {
        const defaultRouteConfig = state.layoutRouteConfigs.find(i => !!i.default);
        if (!!defaultRouteConfig) {
          history!.replace(defaultRouteConfig.path);
        }
      }
      microApp.defer.reset();
      // console.log('microApp.defer.loadMicroReadyMap', { ...microApp.defer.loadMicroReadyMap });

      return () => {
        return currentRoute.value?.render() || '...';
      };
    },
  });

  const render = () => <Render/>;

  /**
   * 子应用自带路由的话，这里是构建子应用的路由publicPath；
   * @author  韦胜健
   * @date    2024/2/22 11:45
   */
  const buildMicroPublicPath = (param?: { microConfig?: iMicroConfig, subMicroPublicPath?: string }) => {
    const cr = currentRoute.value;
    if (!cr) {
      throw new Error('currentRoute is empty!');
    }
    const stringList = [
      microApp.baseRoutePublicPath.get(),
      cr.path,
    ];
    if (!!param?.microConfig) {
      stringList.push(param.microConfig.id);
    }
    if (!!param?.subMicroPublicPath) {
      let subMicroPublicPath = param.subMicroPublicPath;
      if (/https?:\/\//.test(subMicroPublicPath)) {
        const url = new URL(subMicroPublicPath);
        subMicroPublicPath = url.pathname;
      }
      stringList.push(subMicroPublicPath);
    }

    return pathJoin(stringList.join('/'));
  };

  const refer: iMicroApp['route'] = {
    state,
    history: history!,
    defineLayoutRoute,
    definePageRoute,
    matchPageRoute,
    render,
    buildMicroPublicPath,
  };

  return refer;
});
